home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-06 / qb_ipx.zip / CHAT.BAS < prev    next >
BASIC Source File  |  1992-08-03  |  19KB  |  585 lines

  1. '--------------------------------------------------------------------'
  2. '                 CHAT for QuickBASIC using Riceware's               '
  3. '                             IPX Library.                           '
  4. '--------------------------------------------------------------------'
  5. '
  6. DEFINT A-Z
  7. DECLARE SUB RelenquishControl ()
  8. DECLARE SUB SocketListen ()
  9. DECLARE SUB CloseSocket (Socket%)
  10. DECLARE SUB SendPacket (CompleteCode%, InUseFlag%)
  11. DECLARE SUB OpenSocket (Socket%, Status%, SocketNumberReturned%)
  12. DECLARE SUB IPXMarker (Interval%)
  13. DECLARE SUB GetMyAddress (MyNetwork$, MyNode$, MyNetworkHex$, MyNodeHex$)
  14. DECLARE SUB IPXSchedule (DelayTicks%)
  15. DECLARE SUB IPXDisconnect (DNet$, DNode$, DSock$)
  16. DECLARE SUB IPXCancelR (CompleteCode%)
  17. DECLARE SUB IPXCancelS (CompleteCode%)
  18. DECLARE FUNCTION SplitWordLo% (TheWord%)
  19. DECLARE FUNCTION SplitWordHi% (TheWord%)
  20. DECLARE FUNCTION IPXInstalled% ()
  21. DECLARE FUNCTION TurnToHex$ (Variable$)
  22. DECLARE FUNCTION HexToBinary$ (Variable$)
  23. '
  24. '           Define the DOS Interrupt registers.
  25. '
  26. TYPE RegTypeX
  27.    AX    AS INTEGER
  28.    BX    AS INTEGER
  29.    CX    AS INTEGER
  30.    DX    AS INTEGER
  31.    BP    AS INTEGER
  32.    SI    AS INTEGER
  33.    DI    AS INTEGER
  34.    FLAGS AS INTEGER
  35.    DS    AS INTEGER
  36.    ES    AS INTEGER
  37. END TYPE
  38. '
  39. '              This is the Event Control Block Structure.
  40. '
  41. TYPE ECBStructure
  42.    LinkAddressOff AS INTEGER
  43.    LinkAddressSeg AS INTEGER
  44.    ESRAddressOff  AS INTEGER
  45.    ESRAddressSeg  AS INTEGER
  46.    InUse       AS STRING * 1
  47.    CompCode    AS STRING * 1
  48.    SockNum     AS INTEGER
  49.    IPXWorkSpc  AS SINGLE
  50.    DrvWorkSpc  AS STRING * 12
  51.    ImmAdd      AS STRING * 6
  52.    FragCount   AS INTEGER
  53.    FragAddOfs  AS INTEGER
  54.    FragAddSeg  AS INTEGER
  55.    FragSize    AS INTEGER
  56. END TYPE
  57. '
  58. '              This is the IPX Packet Structure.
  59. '
  60. TYPE FullNetAddress
  61.    NetWork     AS STRING * 4
  62.    Node        AS STRING * 6
  63.    Socket      AS STRING * 2
  64. END TYPE
  65. '
  66. TYPE IPXHeader
  67.    Checksum    AS INTEGER
  68.    Length      AS INTEGER
  69.    Control     AS STRING * 1
  70.    PacketType  AS STRING * 1
  71.    DestNet     AS STRING * 4
  72.    DestNode    AS STRING * 6
  73.    DestSocket  AS STRING * 2
  74.    SourNet     AS STRING * 4
  75.    SourNode    AS STRING * 6
  76.    SourSock    AS STRING * 2
  77.    '
  78.    '           Send / Receive one character at a time.
  79.    '
  80.    Datagram    AS STRING * 1
  81. END TYPE
  82. '
  83. DIM SHARED IPXS AS IPXHeader, IPXR AS IPXHeader
  84. DIM SHARED ECBS AS ECBStructure, ECBR AS ECBStructure
  85. DIM SHARED InReg AS RegTypeX, OutReg AS RegTypeX
  86. DIM SHARED Disconnect AS FullNetAddress
  87. DIM SHARED CompleteCode, InUseFlag, Socket%(2)
  88. '
  89. IF IPXInstalled = 0 THEN
  90.    PRINT "IPX.COM is not installed."
  91.    END
  92. END IF
  93. '
  94. CLS
  95. '
  96. '              Just dynamically assigned sockets I picked at
  97. '              random. Gee, I hope no one else is using them!
  98. '              Below is a quick way to open all sockets needed.
  99. '
  100. Socket(1) = &H6382: '          initial send
  101. Socket(2) = &H6383: '          initial listen
  102. Send = Socket(1)
  103. Listen = Socket(2)
  104. '
  105. FOR Socket = Socket(1) TO Socket(2)
  106.    CALL OpenSocket(Socket, Status%, SocketNumberReturned%)
  107.    IF Status = &HFE THEN
  108.       PRINT "No Send socket available. Change SHELL.CFG and try again."
  109.       SYSTEM
  110.    END IF
  111.    '
  112.    IF Status <> 0 THEN
  113.       PRINT USING "Unknown error opening Socket ######. Status: ###### "; Socket; Status
  114.       SYSTEM
  115.    END IF
  116.    PRINT USING "Opened Socket ######."; Socket
  117. NEXT
  118. '
  119. '                 Check for broadcasts on Socket #1. This is the
  120. '                 initial SEND socket: if this program is being
  121. '                 run on another computer, it will be sending on
  122. '                 Socket(1), so THIS computer will LISTEN on #1
  123. '                 and SEND on #2. The other computer will be
  124. '                 listening on #2. Maybe.
  125. '
  126. IPXS.Checksum = 0: '                    Will be set by IPX.COM
  127. IPXS.Length = LEN(IPXS): '              Size, with all fragments
  128. IPXS.Control = CHR$(0): '               Set by IPX.COM
  129. IPXS.PacketType = CHR$(0): '            Zero equals "unknown"
  130. IPXS.DestNet = STRING$(4, &H0): '       default network
  131. IPXS.DestNode = STRING$(6, &HFF): '     broadcast FFFFFFFFFFFF
  132. IPXS.DestSocket = MKI$(Socket(1)): '    Broadcast on the send socket
  133. IPXS.SourSock = MKI$(&H740): '          Random. Not needed.
  134. IPXS.Datagram = CHR$(26): '             The data to send. 1 character.
  135. '
  136. ECBS.ESRAddressOff = 0: '               No event service request
  137. ECBS.ESRAddressSeg = 0: '               No event service request
  138. ECBS.SockNum = Socket(1): '             Broadcast on the send socket
  139. ECBS.ImmAdd = STRING$(6, &HFF): '       Nearest Network
  140. ECBS.FragCount = 1: '                   One fragment
  141. ECBS.FragAddOfs = VARPTR(IPXS): '       Offset of IPX send block
  142. ECBS.FragAddSeg = VARSEG(IPXS): '       Segment of IPX send block
  143. ECBS.FragSize = LEN(IPXS): '            Length of IPX send block
  144. '
  145. '                 Send the packet. This call will return immediately,
  146. '                 and IPX.COM will do its best to deliver the packet
  147. '                 while in the background. When first called, this
  148. '                 routine sets the Event Control Block's INUSE flag
  149. '                 to 255 (&HFF). The DO-LOOP waits for the INUSE
  150. '                 flag to go to zero, while surrendering time to
  151. '                 the Network Interface Card's Device Driver.
  152. '
  153. CALL SendPacket(SendCompleteCode, SendInUseFlag)
  154. PRINT "Broadcast packet was sent."
  155. '
  156. DO
  157.    CALL RelenquishControl
  158.    SendInUseFlag = ASC(ECBS.InUse)
  159. LOOP WHILE SendInUseFlag = &HFF
  160. '
  161. '                 If the INUSE flag went from &HFF to something
  162. '                 other than zero, there was an error; probably
  163. '                 a hardware error.
  164. '
  165. IF SendInUseFlag <> 0 THEN
  166.    PRINT "Send error: "; HEX$(SendInUseFlag)
  167.    FOR S = 1 TO 2
  168.       CALL CloseSocket(Socket(S))
  169.    NEXT
  170.    SYSTEM
  171. END IF
  172. '
  173. '                 Now go into listen mode. If there is another
  174. '                 computer out there, it will be listening AND
  175. '                 sending a broadcast. We do not set up IPXR.
  176. '
  177. ECBR.ESRAddressOff = 0: '               No event service request
  178. ECBR.ESRAddressSeg = 0: '               No event service request
  179. ECBR.SockNum = Socket(2): '             Our LISTEN socket
  180. ECBR.FragCount = 1: '                   One fragment
  181. ECBR.FragAddOfs = VARPTR(IPXR): '       Offset of IPX listen block
  182. ECBR.FragAddSeg = VARSEG(IPXR): '       Segment of IPX listen block
  183. ECBR.FragSize = LEN(IPXR): '            Length of IPX listen block
  184. '
  185. CALL SocketListen
  186. '
  187. '                 Wait for the packet to arrive. If one does,
  188. '                 the INUSE flag will go from &HFE to &H00.
  189. '                 Every three seconds, send a broadcast.
  190. '
  191. PRINT "Listening. Hit any key to quit."
  192. Ti# = TIMER
  193. DO
  194.    ListenInUseFlag = ASC(ECBR.InUse)
  195.    IF ListenInUseFlag = 0 THEN EXIT DO
  196.    IF INKEY$ <> "" THEN EXIT DO
  197.    '
  198.    '              After waiting for three seconds, we have the
  199.    '              program cancel the listen and any send packet
  200.    '              that might be out there from this computer.
  201.    '
  202.    IF TIMER >= (Ti# + 3) THEN
  203.       '
  204.       '           Cancel the listen and send.
  205.       '
  206.       CALL IPXCancelR(CompleteCode%)
  207.       CALL IPXCancelS(CompleteCode%)
  208.       '
  209.       '           Now we swap sockets. Trickie, ain't it? In this
  210.       '           way, a conversation will take no longer than
  211.       '           6 and 1/18 seconds to start, worst case. Most
  212.       '           conversations (~90%) will occur at 3 1/18 seconds.
  213.       '
  214.       IF Send = Socket(1) THEN
  215.          Send = Socket(2)
  216.          Listen = Socket(1)
  217.       ELSE
  218.          Send = Socket(1)
  219.          Listen = Socket(2)
  220.       END IF
  221.       '
  222.       '           Since the Listen Event Control Block is already
  223.       '           set up to point to the Listen IPX header, all
  224.       '           we need to do is tell it to use the new socket.
  225.       '
  226.       ECBR.SockNum = Listen
  227.       CALL SocketListen
  228.       '
  229.       '           Since the Send Event Control Block is already
  230.       '           set up to point to the Send IPX header, all
  231.       '           we need to do is tell it to use the new socket.
  232.       '
  233.       IPXS.DestSocket = MKI$(Send)
  234.       ECBS.SockNum = Send
  235.       Ti# = TIMER
  236.       CALL SendPacket(SendCompleteCode, SendInUseFlag)
  237.       PRINT "Cyclical broadcast packet was sent. ";
  238.       PRINT USING "Sending on ##### and Listening on #####"; Send; Listen
  239.       '
  240.       '           Surrender time to the device driver / NIC.
  241.       '
  242.       DO
  243.          CALL RelenquishControl
  244.          SendInUseFlag = ASC(ECBS.InUse)
  245.       LOOP WHILE SendInUseFlag = &HFF
  246.    END IF
  247. LOOP
  248. '
  249. '                 The Listen INUSE flag will remain &HFE until a
  250. '                 packet is received. Therefore, if we are here,
  251. '                 it must be from an EXIT DO. Since only a user's
  252. '                 keystroke could put us here, that means the
  253. '                 user wanted to quit the listen loop and exit.
  254. '
  255. IF ListenInUseFlag <> 0 THEN
  256.    PRINT "User canceled listen."
  257.    FOR S = 1 TO 2
  258.       CALL CloseSocket(Socket(S))
  259.    NEXT
  260.    SYSTEM
  261. END IF
  262. '
  263. '                 If we got this far, it means a packet was received.
  264. '                 Get the source address of the packet. From now on
  265. '                 we will send to this node, and NOT broadcast.
  266. '
  267. SNet$ = TurnToHex$(IPXR.SourNet)
  268. SNode$ = TurnToHex$(IPXR.SourNode)
  269. SSoc$ = TurnToHex$(IPXR.SourSock)
  270. '
  271. '                 If we got the packet on socket #1, we set up
  272. '                 all future listens to socket #1, and sends on
  273. '                 socket #2. If the converse is true, we do the
  274. '                 opposite, naturally. Cleaver, ain't it?
  275. '
  276. IF IPXR.SourSock = MKI$(Socket(1)) THEN
  277.    Send = Socket(2)
  278.    Listen = Socket(1)
  279. ELSE
  280.    Send = Socket(1)
  281.    Listen = Socket(2)
  282. END IF
  283. '
  284. '                 Tell the other computer that we saw it, by
  285. '                 sending a carriage return.
  286. '
  287. IPXS.Datagram = CHR$(13): '             The data to send. 1 character.
  288. IPXS.DestSocket = MKI$(Send): '         New SEND socket
  289. ECBS.SockNum = Send: '                  Our SEND socket
  290. '
  291. CALL SendPacket(SendCompleteCode, SendInUseFlag)
  292. PRINT "Acknowledgement broadcast packet was sent."
  293. '
  294. DO
  295.    CALL RelenquishControl
  296.    SendInUseFlag = ASC(ECBS.InUse)
  297. LOOP WHILE SendInUseFlag = &HFF
  298. '
  299. '                    Set the Destination Address into variables.
  300. '
  301. PRINT
  302. LOCATE , , 1, 0, 7
  303. DNode$ = IPXR.SourNode
  304. DNet$ = IPXR.SourNet
  305. DIAdd$ = ECBR.ImmAdd
  306. '
  307. PRINT "Received chat request. Node: "; TurnToHex$(IPXR.SourNode)
  308. PRINT "Hit ESC to quit the chat."
  309. '
  310. PRINT
  311. DO
  312.    '
  313.    '           Get user input if any. User imput may only occur
  314.    '           when the Send Event Control Block is not in use.
  315.    '
  316.    SendInUseFlag = ASC(ECBS.InUse)
  317.    IF SendInUseFlag = 0 THEN
  318.       '
  319.       '        Checks the keyboard buffer.
  320.       '
  321.       A$ = INKEY$
  322.       '
  323.       '        If not blank, there was a key press.
  324.       '
  325.       IF A$ <> "" THEN
  326.          IF A$ = CHR$(27) THEN
  327.             '
  328.             '
  329.             '        Does the user want to exit the program? Looks like
  330.             '        it, so let the other computer know that fact. Send
  331.             '        an ESC character.
  332.             '
  333.             IPXS.Checksum = 0
  334.             IPXS.Length = LEN(IPXS)
  335.             IPXS.Control = CHR$(0)
  336.             IPXS.PacketType = CHR$(0)
  337.             IPXS.DestNet = DNet$
  338.             IPXS.DestNode = DNode$
  339.             IPXS.DestSocket = MKI$(Send)
  340.             IPXS.SourSock = MKI$(1)
  341.             IPXS.Datagram = CHR$(27)
  342.             '
  343.             ECBS.SockNum = Send
  344.             ECBS.ImmAdd = DIAdd$
  345.             ECBS.FragCount = 1
  346.             ECBS.FragAddOfs = VARPTR(IPXS)
  347.             ECBS.FragAddSeg = VARSEG(IPXS)
  348.             ECBS.FragSize = LEN(IPXS)
  349.             ' 
  350.             CALL SendPacket(CompleteCode, SendInUseFlag)
  351.             SendInUseFlag = ASC(ECBS.InUse)
  352.             DO
  353.                CALL RelenquishControl
  354.                SendInUseFlag = ASC(ECBS.InUse)
  355.             LOOP WHILE SendInUseFlag = &HFF
  356.             '
  357.             '           Tell the other computer's device that
  358.             '           you no longer want to talk.
  359.             '
  360.             CALL IPXDisconnect(DNet$, DNode$, DSock$)
  361.             EXIT DO
  362.          END IF
  363.          '
  364.          '              Did the user hit the backspace key?
  365.          '
  366.          IF A$ = CHR$(8) THEN
  367.             '
  368.             '           Send a LeftCursor, a space, and another
  369.             '           LeftCursor.
  370.             '
  371.             Message$ = CHR$(29) + " " + CHR$(29)
  372.             FOR A = 1 TO 3
  373.                IPXS.Datagram = MID$(Message$, A, 1)
  374.                CALL SendPacket(CompleteCode, SendInUseFlag)
  375.                SendInUseFlag = ASC(ECBS.InUse)
  376.                DO
  377.                   CALL RelenquishControl
  378.                   SendInUseFlag = ASC(ECBS.InUse)
  379.                LOOP WHILE SendInUseFlag = &HFF
  380.             NEXT
  381.             PRINT Message$;
  382.          ELSE
  383.             '
  384.             '           Otherwise, send what the user entered.
  385.             '
  386.             IPXS.Checksum = 0
  387.             IPXS.Length = LEN(IPXS)
  388.             IPXS.Control = CHR$(0)
  389.             IPXS.PacketType = CHR$(0)
  390.             IPXS.DestNet = DNet$
  391.             IPXS.DestNode = DNode$
  392.             IPXS.DestSocket = MKI$(Send)
  393.             IPXS.SourSock = MKI$(1)
  394.             IPXS.Datagram = A$
  395.             '
  396.             ECBS.SockNum = Send
  397.             ECBS.ImmAdd = DIAdd$
  398.             ECBS.FragCount = 1
  399.             ECBS.FragAddOfs = VARPTR(IPXS)
  400.             ECBS.FragAddSeg = VARSEG(IPXS)
  401.             ECBS.FragSize = LEN(IPXS)
  402.             '
  403.             CALL SendPacket(CompleteCode, SendInUseFlag)
  404.             SendInUseFlag = ASC(ECBS.InUse)
  405.             DO
  406.                CALL RelenquishControl
  407.                SendInUseFlag = ASC(ECBS.InUse)
  408.             LOOP WHILE SendInUseFlag = &HFF
  409.             PRINT A$;
  410.          END IF
  411.       END IF
  412.    END IF
  413.    '
  414.    '              Now listen for a packet
  415.    '
  416.    ListenInUseFlag = ASC(ECBR.InUse)
  417.    '
  418.    '              Will be zero if a packet has been received.
  419.    '              Otherwise, the other user has not sent anything.
  420.    '
  421.    IF ListenInUseFlag = 0 THEN
  422.       IF IPXR.Datagram = CHR$(27) THEN
  423.          PRINT "Other User Ended Chat"
  424.          EXIT DO
  425.       ELSE
  426.          '
  427.          '        Print what the other computer user sent.
  428.          '
  429.          PRINT IPXR.Datagram;
  430.       END IF
  431.       '
  432.       ECBR.SockNum = Listen
  433.       ECBR.FragCount = 1
  434.       ECBR.FragAddOfs = VARPTR(IPXR)
  435.       ECBR.FragAddSeg = VARSEG(IPXR)
  436.       ECBR.FragSize = LEN(IPXR)
  437.       CALL SocketListen
  438.    END IF
  439. LOOP
  440. '
  441. '                    If we are here, it means we hit ESC or the
  442. '                    other person did. Close the two sockets.
  443. '
  444. FOR S = 1 TO 2
  445.    CALL CloseSocket(Socket(S))
  446.    PRINT USING "Closed Socket ######."; Socket(S)
  447. NEXT
  448.  
  449. SUB CloseSocket (Socket%)
  450.    InReg.BX = 1
  451.    InReg.AX = 0
  452.    InReg.DX = Socket
  453.    CALL InterruptX(&H7A, InReg, OutReg)
  454. END SUB
  455.  
  456. FUNCTION HexToBinary$ (Variable$)
  457.    IF Variable$ = "" THEN
  458.       HexToBinary$ = ""
  459.    ELSE
  460.       A = LEN(Variable$) MOD 2
  461.       IF A = 1 THEN
  462.          HexToBinary$ = ""
  463.       ELSE
  464.          Temp$ = ""
  465.          FOR A = 1 TO LEN(Variable$) STEP 2
  466.             Temp! = VAL("&H" + MID$(Variable$, A, 2))
  467.             Temp$ = Temp$ + CHR$(Temp!)
  468.          NEXT
  469.          HexToBinary$ = Temp$
  470.       END IF
  471.    END IF
  472. END FUNCTION
  473.  
  474. SUB IPXCancelR (CompleteCode%)
  475.    InReg.BX = 6
  476.    InReg.ES = VARSEG(ECBR)
  477.    InReg.SI = VARPTR(ECBR)
  478.    CALL InterruptX(&H7A, InReg, OutReg)
  479.    CompleteCode = SplitWordLo%(OutReg.AX)
  480.    '
  481.    '                    FC = was canceled
  482. END SUB
  483.  
  484. SUB IPXCancelS (CompleteCode%)
  485.    InReg.BX = 6
  486.    InReg.ES = VARSEG(ECBS)
  487.    InReg.SI = VARPTR(ECBS)
  488.    CALL InterruptX(&H7A, InReg, OutReg)
  489.    CompleteCode = SplitWordLo%(OutReg.AX)
  490.    '
  491.    '                    FC = was canceled
  492. END SUB
  493.  
  494. SUB IPXDisconnect (DNet$, DNode$, DSock$)
  495.    Disconnect.NetWork = DNet$
  496.    Disconnect.Node = DNode$
  497.    Disconnect.Socket = DSock$
  498.    InReg.BX = &HB
  499.    InReg.ES = VARSEG(Disconnect)
  500.    InReg.SI = VARPTR(Disconnect)
  501.    CALL InterruptX(&H7A, InReg, OutReg)
  502. END SUB
  503.  
  504. FUNCTION IPXInstalled%
  505.    InReg.AX = &H7A00
  506.    CALL InterruptX(&H2F, InReg, OutReg)
  507.    AL = SplitWordLo(OutReg.AX)
  508.    IF AL = &HFF THEN IPXInstalled = 1 ELSE IPXInstalled = 0
  509. END FUNCTION
  510.  
  511. SUB OpenSocket (Socket%, Status%, SocketNumberReturned%)
  512.    InReg.BX = 0
  513.    InReg.AX = 0
  514.    InReg.DX = Socket
  515.    CALL InterruptX(&H7A, InReg, OutReg)
  516.    Status = SplitWordLo(OutReg.AX)
  517.    SocketNumberReturned = OutReg.DX
  518.    '
  519.    '           Completion status
  520.    '                    00 successful
  521.    '                    FF open already
  522.    '                    FE socket table is full
  523. END SUB
  524.  
  525. SUB RelenquishControl
  526.    DEFINT A-Z
  527.    InReg.AX = 0
  528.    InReg.BX = &HA
  529.    CALL InterruptX(&H7A, InReg, OutReg)
  530. END SUB
  531.  
  532. SUB SendPacket (CompleteCode%, InUseFlag%)
  533.    InReg.BX = 3
  534.    InReg.ES = VARSEG(ECBS)
  535.    InReg.SI = VARPTR(ECBS)
  536.    CALL InterruptX(&H7A, InReg, OutReg)
  537.    CompleteCode = ASC(ECBS.CompCode)
  538.    InUseFlag = ASC(ECBS.InUse)
  539.    '
  540.    '        Error codes:
  541.    '              00    sent
  542.    '              FC    canceled
  543.    '              FD    malformed packet
  544.    '              FE    no listener (undelivered)
  545.    '              FF    hardware failure
  546. END SUB
  547.  
  548. SUB SocketListen
  549.    InReg.BX = 4
  550.    InReg.ES = VARSEG(ECBR)
  551.    InReg.SI = VARPTR(ECBR)
  552.    CALL InterruptX(&H7A, InReg, OutReg)
  553.    CompleteCode = ASC(ECBR.CompCode)
  554.    InUseFlag = ASC(ECBR.InUse)
  555.    '
  556.    '        Completion codes:
  557.    '              00    received
  558.    '              FC    canceled
  559.    '              FD    packet overflow
  560.    '              FF    socket was closed
  561.    '              FE    Listening
  562. END SUB
  563.  
  564. FUNCTION SplitWordHi (TheWord%)
  565.    SplitWordHi = (TheWord% AND &HFF00) / 256
  566. END FUNCTION
  567.  
  568. FUNCTION SplitWordLo (TheWord%)
  569.    SplitWordLo = (TheWord% AND &HFF)
  570. END FUNCTION
  571.  
  572. FUNCTION TurnToHex$ (Variable$)
  573.    Temp$ = ""
  574.    FOR Byte = 1 TO LEN(Variable$)
  575.       Value! = ASC(MID$(Variable$, Byte, 1))
  576.       IF Value! < 15 THEN
  577.          Temp$ = Temp$ + "0" + HEX$(Value!)
  578.       ELSE
  579.          Temp$ = Temp$ + HEX$(Value!)
  580.       END IF
  581.    NEXT
  582.    TurnToHex$ = Temp$
  583. END FUNCTION
  584.  
  585.